<!doctype html>
<html>
    <head>
        <title>VirgilCrypto browser test</title>
        <script src="https://unpkg.com/lodash@4.17.5/lodash.js"></script>
        <script src="https://unpkg.com/benchmark@2.1.4/benchmark.js"></script>
        <script src="@WRAPPER_TARGET@.js"></script>
    </head>
    <body>
    <script type="text/javascript">
        function test_encryption(lib) {
            console.time("encryption/decryption");
            var pwd = lib.VirgilByteArray.fromUTF8("password");
            var keys = lib.VirgilKeyPair.generateRecommended(pwd);
            var certId = lib.VirgilByteArray.fromUTF8("17648c7e-9ca3-4707-bdc6-a5c57b7a18fc");
            var data = lib.VirgilByteArray.fromUTF8("data to be encrypted");
            var cipher = new lib.VirgilCipher();
            cipher.addKeyRecipient(certId, keys.publicKey());
            var encryptedData = cipher.encrypt(data, true);
            var decryptedData = cipher.decryptWithKey(encryptedData, certId, keys.privateKey(), pwd);
            console.log(decryptedData.toUTF8());
            pwd.delete();
            keys.delete();
            certId.delete();
            data.delete();
            cipher.delete();
            encryptedData.delete();
            decryptedData.delete();
            console.timeEnd("encryption/decryption");
        };
        function test_stream_encryption(lib) {
            console.time("stream encryption/decryption");
            var pwd = lib.VirgilByteArray.fromUTF8("password");
            var keys = lib.VirgilKeyPair.generateRecommended(pwd);
            var certId = lib.VirgilByteArray.fromUTF8("17648c7e-9ca3-4707-bdc6-a5c57b7a18fc");
            var data = lib.VirgilByteArray.fromUTF8("data to be encrypted");
            var cipher = new lib.VirgilStreamCipher();
            cipher.addKeyRecipient(certId, keys.publicKey());

            var dataSource = new lib.VirgilStreamDataSource(data.toUint8Array(), 1);
            var dataSink = new lib.VirgilStreamDataSink();
            cipher.encrypt(dataSource, dataSink, true);

            var encrypedDataSource = new lib.VirgilStreamDataSource(dataSink.getBytes(), 2);
            var decryptedDataSink = new lib.VirgilStreamDataSink();

            cipher.decryptWithKey(encrypedDataSource, decryptedDataSink, certId, keys.privateKey(), pwd);

            var decryptedData = lib.VirgilByteArray.fromUint8Array(decryptedDataSink.getBytes());

            console.log(decryptedData.toUTF8());
            pwd.delete();
            keys.delete();
            certId.delete();
            data.delete();
            cipher.delete();
            decryptedData.delete();
            dataSource.delete();
            dataSink.delete();
            encrypedDataSource.delete();
            decryptedDataSink.delete();
            console.timeEnd("stream encryption/decryption");
        };
        function test_sign(lib) {
            console.time("sign/verify");
            var pwd = lib.VirgilByteArray.fromUTF8("");
            var keys = lib.VirgilKeyPair.generateRecommended(pwd);
            var data = lib.VirgilByteArray.fromUTF8("data to be signed");
            var signer = new lib.VirgilSigner();
            var sign = signer.sign(data, keys.privateKey(), pwd);
            var verified = signer.verify(data, sign, keys.publicKey());
            console.log("Data verification " + (verified ? "passed" : "failed"));
            pwd.delete();
            keys.delete();
            data.delete();
            signer.delete();
            sign.delete();
            console.timeEnd("sign/verify");
        };

        function encrypt(lib, data, publicKey, certId) {
            var cipher = new lib.VirgilCipher();
            cipher.addKeyRecipient(certId, publicKey);
            var ciphertext = cipher.encrypt(data, true);
            cipher.delete();
            return ciphertext;
        }

        function decrypt(lib, ciphertext, privateKey, certId) {
            var cipher = new lib.VirgilCipher();
            var decrypted = cipher.decryptWithKey(ciphertext, certId, privateKey, lib.VirgilByteArray.fromUTF8(''));
            cipher.delete();
            return decrypted;
        }

        function calcSignature(lib, data, privateKey) {
            var signer = new lib.VirgilSigner();
            var signature = signer.sign(data, privateKey, lib.VirgilByteArray.fromUTF8(""));
            signer.delete();
            return signature;
        }

        function verifySignature(lib, data, signature, publicKey) {
            var signer = new lib.VirgilSigner();
            var verified = signer.verify(data, signature, publicKey);
            signer.delete();
            return verified;
        }

        function runTests(instance) {
            console.log('Starting tests');

            test_encryption(instance);
            test_stream_encryption(instance);
            test_sign(instance);
        }

        function runBenchmarks(instance) {
            console.log('Starting benchmarks');
            var suite = new Benchmark.Suite();

            // key pair for encryption / decryption
            var eKeypair = instance.VirgilKeyPair.generateRecommended(
                instance.VirgilByteArray.fromUTF8('')
            );

            // key pair for generating / verifying signature
            var sKeypair = instance.VirgilKeyPair.generateRecommended(
                instance.VirgilByteArray.fromUTF8('')
            );

            // 32 random bytes to be used as RECIPIENT_ID
            var eCertId = instance.VirgilByteArray.fromUint8Array(
                window.crypto.getRandomValues(new Uint8Array(32))
            );

            // 1kB of data to encrypt / decrypt
            var eData = instance.VirgilByteArray.fromUint8Array(
                window.crypto.getRandomValues(new Uint8Array(1024))
            );
            var eCiphertext = encrypt(instance, eData, eKeypair.publicKey(), eCertId);

            // 1kB of data to sign / verify
            var sData = instance.VirgilByteArray.fromUint8Array(
                window.crypto.getRandomValues(new Uint8Array(1024))
            );
            var sSignature = calcSignature(instance, sData, sKeypair.privateKey());

            suite.add('KeyPair#generateRecommended without password', function () {
                var keypair = instance.VirgilKeyPair.generateRecommended(
                    instance.VirgilByteArray.fromUTF8('')
                );
                keypair.delete();
            })
            .add('KeyPair#generateRecommended with password', function () {
                var keypair = instance.VirgilKeyPair.generateRecommended(
                    instance.VirgilByteArray.fromUTF8('passphrase')
                );
                keypair.delete();
            })
            .add('KeyPair#generate NIST-256 without password', function() {
                var keypair = instance.VirgilKeyPair.generate(
                    instance.VirgilKeyPair.Type.EC_SECP256R1,
                    instance.VirgilByteArray.fromUTF8('')
                );
                keypair.delete();
            })
            .add('KeyPair#generate NIST-256 with password', function() {
                var keypair = instance.VirgilKeyPair.generate(
                    instance.VirgilKeyPair.Type.EC_SECP256R1,
                    instance.VirgilByteArray.fromUTF8('passphrase')
                );
                keypair.delete();
            })
            .add('Cipher#encrypt', function () {
                encrypt(instance, eData, eKeypair.publicKey(), eCertId).delete();
            })
            .add('Cipher#decryptWithKey', function () {
                decrypt(instance, eCiphertext, eKeypair.privateKey(), eCertId).delete();
            })
            .add('Signer#sign', function () {
                calcSignature(instance, sData, sKeypair.privateKey()).delete();
            })
            .add('Signer#verify', function () {
                verifySignature(instance, sData, sSignature, sKeypair.publicKey());
            })
            .on('cycle', function (event) {
              console.log(String(event.target));
            })
            .on('complete', function () {
              console.log('Done');
            })
            .run();
        }

        __virgilCrypto().then(function (instance) {
            console.log(instance.VirgilVersion.asString());
            runTests(instance);
            console.log('');
            runBenchmarks(instance);
        });
    </script>
    </body>
</html>
